/*****************************************************************************/
/*                                                                           */
/*    Domino Operation System Driver Module                                  */
/*                                                                           */
/*    Copyright (C) 2008 Laszlo Arvai                                        */
/*                                                                           */
/*    ------------------------------------------------------------------     */
/*    drvDOGM132SPI - DOGM132x64 Graphics LCD Driver                         */
/*****************************************************************************/

///////////////////////////////////////////////////////////////////////////////
// Includes
#include <krnlSystemTimer.h>
#include "drvIOConfig.h"
#include "guiLCDDriver.h"
#include "sysSettings.h"
#include "guiFrameBuffer.h"

///////////////////////////////////////////////////////////////////////////////
// Const 
#define DOGM_INIT_BYTES 14
#define DOGM_COLUMN_MASK 0x0f
#define DOGM_CMD_COLUMN_HI_SET 0x10
#define DOGM_CMD_COLUMN_LO_SET 0x00
#define DOGM_CMD_PAGE_SET 0xb0
#define DOGM_PAGE_MASK 0x0f
#define DOGM_COLUMN_COUNT 132
#define DOGM_ROW_COUNT 4

///////////////////////////////////////////////////////////////////////////////
// Module local variables
const dosByte dogm_init_data[DOGM_INIT_BYTES] = {0x40,0xA1,0xC0,0xA6,0xA2,0x2F,0xF8,0x00,0x23,0x81,0x1F,0xAC,0x00,0xAF};

///////////////////////////////////////////////////////////////////////////////
// Global variables

///////////////////////////////////////////////////////////////////////////////
// Init LCD driver
void guiInitLCDDriver(void)
{
  dosByte i;
	dosByte j;
	
	// init pins
	InitLCDRESET();
	InitLCDSPI();
	InitLCDCSB();
	InitLCDRS();

	// issue reset
	LCDRESET( PIN_LOW );

	// power up delay
	krnlDelay( 200 );
	
	LCDRESET( PIN_HIGH );

	// short delay
	krnlDelay( 2 );

	// Command Mode, set RS low
	LCDRS( PIN_LOW );
	
	// chip select
	LCDCSB( PIN_LOW );

	// send init bytes	
	for (i=0; i < DOGM_INIT_BYTES; i++)	
	{
		LCDSendAsynchronByte(dogm_init_data[i]);
		LCDReceiveAsynchronByte();
  }

	// clear graphics display
	for( j = 0; j < DOGM_ROW_COUNT; j++ )
	{
		// Command Mode, set RS low
		LCDRS( PIN_LOW );

		LCDSendAsynchronByte(DOGM_CMD_COLUMN_HI_SET);
		LCDReceiveAsynchronByte();

		LCDSendAsynchronByte(DOGM_CMD_COLUMN_LO_SET);
		LCDReceiveAsynchronByte();

		LCDSendAsynchronByte(DOGM_CMD_PAGE_SET | j);
		LCDReceiveAsynchronByte();

		// Data Mode, set RS high
		LCDRS( PIN_HIGH );

  	for(i = 0; i < DOGM_COLUMN_COUNT; ++i)
  	{
	  	LCDSendAsynchronByte(0);
			LCDReceiveAsynchronByte();
		}
	}

	// remove chip select
	LCDCSB( PIN_HIGH );

	// turn backlight on
	guiEnableBacklight(dosTrue);
}

///////////////////////////////////////////////////////////////////////////////
// Clear character screen
void guiTextClearScreen(void)
{
	// no character mode
}

///////////////////////////////////////////////////////////////////////////////
// Set text screen cursor pos
void guiTextSetCursorPos( dosByte in_x, dosByte in_y )
{
	// no character mode
}

///////////////////////////////////////////////////////////////////////////////
// Write character onto the text screen
void guiTextWriteChar(dosChar in_char )
{
	// no character mode
}

///////////////////////////////////////////////////////////////////////////////
// Update canvas
void guiUpdateCanvas( dosInt16 in_left, dosInt16 in_top, dosInt16 in_right, dosInt16 in_bottom )
{
	dosByte start_column = in_left;
	dosByte end_column = in_right;
	dosByte first_page = in_top / 8;
	dosByte last_page = in_bottom / 8;
	dosByte page;
	dosByte column;
	dosByte byte_buffer;
	dosWord frame_buffer_address;
	dosByte i;
	dosByte bit_mask;
	
	// chip select
	LCDCSB( PIN_LOW );

	for( page = first_page; page <= last_page; page++ )
	{
		// Command Mode, set RS low
		LCDRS( PIN_LOW );

		LCDSendAsynchronByte(DOGM_CMD_COLUMN_HI_SET | (start_column >> 4) & 0x0f );
		LCDReceiveAsynchronByte();

		LCDSendAsynchronByte(DOGM_CMD_COLUMN_LO_SET | (start_column & 0x0f) );
		LCDReceiveAsynchronByte();

		LCDSendAsynchronByte(DOGM_CMD_PAGE_SET | page);
		LCDReceiveAsynchronByte();

		// Data Mode, set RS high
		LCDRS( PIN_HIGH );

		// send data bytes
		for( column = start_column; column <= end_column; column++ )
		{
			// calculate frame buffer address
			frame_buffer_address = column	/ 8 + page * 8 * guiFRAME_BUFFER_ROW_LENGTH;
			
			// calculate byte to send
			byte_buffer = 0;
			bit_mask = 1 << (7-(column % 8));
			for( i = 0; i < 8; i++ )
			{
				byte_buffer >>= 1;

				if( (g_frame_buffer[frame_buffer_address] & bit_mask) != 0 )
					byte_buffer |= 0x80;
				
				frame_buffer_address += guiFRAME_BUFFER_ROW_LENGTH;
			}	 	
			
			// wait for previous send to finish
			LCDReceiveAsynchronByte();
			
			// send byte
			LCDSendAsynchronByte(byte_buffer);
		}	
		
		// wait for last byte to finish
		LCDReceiveAsynchronByte();
	}	

	// remove chip select
	LCDCSB( PIN_HIGH );
}

///////////////////////////////////////////////////////////////////////////////
// Turn backlight on and off
void guiEnableBacklight(dosBool in_enabled)
{
	if( in_enabled )
		LCD_BACKLIGHT(PIN_HIGH);
	else
		LCD_BACKLIGHT(PIN_LOW);
}

